#ifndef __XML_PARSER_H__
  #define __XML_PARSER_H__

#include <string>
#include <map>

#include "xml_node.h"

using namespace std;

//! Simple XML Parser

/*!
A simple implementation for an XML Parser. This class can be used to parse XML files and XML strings.

When working with large XML files, there may be some problems with the stack size.
1MB in MS-Compiler & 8MB in G++ are defaults.

1MB is not large enough for large XML files, since this implementation is a recursive one.
If necessary, you can increase it:
project properties >> linker >> system >> stack reserve size (in bytes)
example: 8388608 = 8MB

For internationalized strings UTF8 must be used.

Currently not supported feature(s):
\li XML name spaces
\li XML comments (will be ignored)
\li contents after [or between] child nodes are ignored.
For example:
\code
<node1>
  hello <b>John</b>. How are you?
</node1>
\endcode
will result as:
\code
<node1>
  hello <b>John</b>
</node1>
\endcode

Implementation date: 2008

Usage:

\code
xml_node xn;
xml_parser xp;
xp.parse_file("my_xml_file.xml", &xn);
cout << xn.get_name() << endl;
cout << xn.get_content() << endl;

string s1;
xn.to_string(s1, true);
\endcode
*/

class xml_parser {
friend class xml_serializable;

private:
  static map<const char*, const char*> special_tags; // these tag(s) will be ignored
  static const string allowed_symbols; // allowed symbol(s) in attribute names and tag names

  FILE *xml_file;
  char *buffer;
  bool error_occurred;

  xml_parser &operator=(const xml_parser &xp); // not allowed
  xml_parser(const xml_parser &xp); // not allowed

  //! deletes the "buffer" and sets it back to null
  void reset_the_buffer();

  void open(const string &file_name);
  void close();

  //! returns true if it is an opening tag, may also change the 'error_occurred' variable
  bool get_next_tag(string &output, size_t &index);
  size_t get_tag_name(const string &input, string &output) const;
  void ignore_spaces(const string &input, size_t &index) const;
  void get_attribute_name(const string &input, size_t &index, string &output) const;
  void add_attributes_to_node(const string &input, xml_node *node, size_t &index) const;
  void add_content_to_node(xml_node *node, size_t &index) const;
  bool is_empty_element(const string &input) const;
  void parse_children(xml_node *node, size_t &index, bool is_root_node);

  void parse_and_check(xml_node *node);

public:

  //! parses the given XML file and stores its XML tree into the given node (may throw an exception)
  void parse_file(const string &file_name, xml_node *node);

  //! parses the given XML string and stores its XML tree into the given node
  void parse_string(const string &xml_string, xml_node *node);

  //! default constructor
  xml_parser();

  //! destructor (non-virtual: please do not inherit from this class)
  ~xml_parser();
}; // class xml_parser

#endif
